/*************************************************
* Copyright(c) free                              *
* Beijing Jiaotong University                    *
* TEAM: Wasabi                                   *
* AUTHOR: Li Yi          			 *
* This file is used to cut Chinese sentences into* 
* separate words and return its pronouciation.   *
* Version 1.0 2011-01-6                          *
*************************************************/
	
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <wchar.h>
#include <iconv.h>
#include <stdlib.h>
#include "../include/convert.h"
#include "../include/DicManager.h"

#define FORWARD 1
#define BACKWARD 2
#define FIRSTCHI 1
#define FIRSTOTHER 2
/***************************************************************************************************
 convert : convert a piece of string buffer from 
 one encode to anther.
 parameter : char* inBuf(in) 
	     The buffer needed to be converted
	     
	     int* inLen(in\out)
             When input it's the length of inBuf,when output it's the length of unconverted words
	     
	     char* outBuf(out)
             When input, it's the buffer prepared for the converted string, you have ensure that it
             has enough space.When output the buffer contains the string which has been converted.
             
	     int* outLen(in\out)
             When input it's the length of outBuf.When output it's the length of space unused in outBuf.
             
	     char* inCode(in)
             The encode form of inBuf.

	     char* outCode(in)
	     The encode form of outBuf.
 return type : int 
        value :  0 when successful
                -1 when failed
 detail descrpition : this function wraps up the iconv functions.You need to give your string needed
 to be converted,and explicitly tell its length.You also need to prepare the memory to store output 
 string ande tell its length,too.It's your resposibility to ensure the output buffer is large enough
 to hold the converted string.Don't forget to add a terminal byte or bytes for your outBuf.             
****************************************************************************************************/
int convert( char* inBuf, int* inLen, char* outBuf, int* outLen, char* inCode,char* outCode ){
    char* pIn;
    char* pOut;

    iconv_t cd;

    cd = iconv_open( outCode, inCode ); //iconv_open

    if( cd == (iconv_t)-1 ){
    printf("iconv_open failure!\n ");
     return -1;
    }
   
    pIn = inBuf;
    pOut = outBuf;
  
    size_t n = iconv(cd,		    //iconv
	(char**)&pIn,
	inLen,
	(char**)&pOut,
	outLen); 
    if( n == (size_t)-1 ){
    	printf("iconv failure!\n");
	return n;
    }
	
    iconv_close(cd);		  //iconv_close	ol
   
    return 0;
}
/*
wchar_t* LookForWord( wchar_t* word )
{
	char pinyin[] = "v5";
        int inLen = strlen( pinyin );
        
	char* pIn;
        char* pOut;
        
        char *out = ( char* )malloc( 6 * sizeof( wchar_t ) );
        memset( out, 0, 6 * sizeof( wchar_t ) );
	int outLen = 5 * sizeof( wchar_t );
   
        pIn = &pinyin[0];
        pOut = &out[0];
        
        int nRet = convert( pIn, &inLen, pOut, &outLen, "UTF8", "UCS4" );
	if( nRet == -1 )
	{
		printf( "LookForWord convert failure!\n" );
 		return NULL;
	}

	if( wcslen( word ) < 2 )
		return ( wchar_t* )out;
	else 
		return NULL;
}*/
/************************************************************************************
 ForwardCutWords : Implementation of maxium forward cutting algorithm
 Parameters : wchar_t* inBuf
              The String needed to be cut
              wchar_t** outBuf
              The pointer to the String after cut
              wchar_t** outPinyin
              The pointer to the pronouciation also cut corresponding to the cut string
 return type : int
        value : 0 when successful
                -1 when failed
 detail discription:You give a inBuf to the function,and it will cut it into separate
 words using maxium forward cutting algorithm.It will also return you the pinyin of inBuf 
 which has also been cut.
 ATTENTION : outBuf and outPinyin are dynamic allocated, you need to free them manually. 
 ChangeLog : 2011-1-4 when words can't be found in dictionary, use "***" to indicate 
             pinyin.                          
************************************************************************************/
int ForwardCutWords( wchar_t* inBuf, wchar_t** outBuf, wchar_t** outPinyin ){
    int inwLen;
    wchar_t* wWords;
    wchar_t* wPinyin;
    wchar_t* wpIn;

    wchar_t wSpace[2];
    memset( wSpace, 0 , 2 * sizeof( wchar_t ) );

    char *pIn,*pOut;
    char* space = " ";
    int inLen = 1;
    int outLen = sizeof( wchar_t );
    pIn = space;
    pOut = ( char* )wSpace;
    int n = convert( pIn, &inLen, pOut, &outLen, "UTF8", "UCS4" );
    if( n == -1 ){ 
       printf( "convert space failure!\n" );
       return n;
    }    
    //get the UCS4 code for " "
    
    char* star = "***";
    wchar_t wStar[4];
    memset( wStar, 0 , 4 * sizeof( wchar_t ) );
    inLen = 3;
    outLen = 3 * sizeof( wchar_t );
    
    pIn = star;
    pOut = ( char* )wStar;
    n = convert( pIn, &inLen, pOut, &outLen, "UTF8", "UCS4" );
    if( n == -1 ){ 
       printf( "ForwardCutWords convert star failure!\n" );
       return n;
    }    
    //get the "***" UCS4
 
    inwLen = wcslen(inBuf);
    *outBuf = ( wchar_t* )malloc( ( inwLen * 2 + 1 ) * sizeof(wchar_t) );
    memset( *outBuf, 0, ( inwLen * 2 + 1 ) * sizeof( wchar_t ) );
    //allocate a space for *outBuf, + 1 for terminal null.
    
    *outPinyin = ( wchar_t* )malloc( (inwLen * 8 + 1 ) * sizeof(wchar_t) );
    memset( *outPinyin, 0, ( inwLen * 8 + 1 ) * sizeof( wchar_t ) );
    //the longest length of pinyin is 7,like "zhuang3",adding a " " make it 8
    
    wpIn = inBuf; 
    while( wcslen(wpIn) != 0 ){
        int nLength = wcslen(wpIn);
        wWords = malloc( ( nLength + 1 ) * sizeof(wchar_t) );
        wcscpy( wWords, wpIn );

        while( wcslen(wWords) > 0 && ( wPinyin = LookForWord(wWords) ) == NULL ) {    
	    if( wcslen( wWords ) == 1 )
                break;
            wchar_t* wTmp = wWords; 
	    wTmp = wTmp + wcslen(wWords) - 1;
            wcsncpy( wTmp, L"\0", 1 );
           //cut the last character in wWords
        }

        wcscat( *outBuf, wWords );
        wcscat( *outBuf, wSpace );
    	
	if( wPinyin != NULL )
            wcscat( *outPinyin, wPinyin );
	else
 	    wcscat( *outPinyin, wStar );
        wcscat( *outPinyin, wSpace );

        wpIn = wpIn + wcslen(wWords);
        //cut wWords from the left of wpIn
	free( wWords );
        wWords = NULL;
    }
    return 0;
}

/************************************************************************************
 BackwardCutWords : Implementation of maxium backward cutting algorithm
 Parameters : wchar_t* inBuf
              the String needed to be cut
              wchar_t** outBuf
              The pointer to the String after cut
              wchar_t** outPinyin
              The pointer to the pronouciation also cut corresponding to the cut string
 return type : int
        value : 0 when successful
                -1 when failed
 detail discription:You give an inBuf to the function,and it will cut it into separate
 words using maxium backward cutting algorithm.It will also return you the pinyin of inBuf 
 which has also been cut.
 ATTENTION : outBuf and outPinyin are dynamic allocated, you need to free them manually.
 
 ChangeLog : 2011-1-4 when words can't be found in dictionary, use "***" to indicate 
             pinyin.                           
************************************************************************************/
int BackwardCutWords( wchar_t* inBuf, wchar_t** outBuf, wchar_t** outPinyin ){
    int inwLen;
    wchar_t* wWords;
    wchar_t* wPinyin;
    wchar_t* wInBuf;
    wchar_t* wRealOut;
    wchar_t* wRealPinyin;

    wchar_t wSpace[2];
    memset( wSpace, 0 , 8);

    char space[] = " ";
    int inLen = 1;
    int outLen = 4;
    char *pIn,*pOut;
    pIn = space;
    pOut = ( char* )wSpace;

    int n = convert( pIn, &inLen, pOut, &outLen, "UTF8", "UCS4" );
    if( n == -1 ){ 
       printf( "BackwardCutWords convert space failure!\n" );
       return n;
    }    
    //get the UCS4 code for " "
    
    char* star = "***";
    wchar_t wStar[4];
    memset( wStar, 0 , 4 * sizeof( wchar_t ) );
    inLen = 3;
    outLen = 3 * sizeof( wchar_t );
    
    pIn = star;
    pOut = ( char* )wStar;
    n = convert( pIn, &inLen, pOut, &outLen, "UTF8", "UCS4" );
    if( n == -1 ){ 
       printf( "ForwardCutWords convert star failure!\n" );
       return n;
    }    
    //get the "***" UCS4

    inwLen = wcslen(inBuf);
    wInBuf = ( wchar_t* )malloc( ( inwLen + 1 ) * sizeof(wchar_t) );
    //make a copy for inBuf,which whose content will be change later on.
    memset ( wInBuf, 0 , (inwLen + 1 ) * sizeof( wchar_t) );
    wcscpy ( wInBuf, inBuf );
            
    *outBuf = ( wchar_t* )malloc( ( inwLen * 2 + 1 ) * sizeof(wchar_t) );
    wRealOut = ( wchar_t * )malloc( ( inwLen * 2 + 1 ) * sizeof(wchar_t) );
    memset( *outBuf, 0, ( inwLen * 2 + 1 ) * sizeof( wchar_t ) );
    memset( wRealOut, 0, ( inwLen * 2 + 1 ) * sizeof( wchar_t ) );
    //allocate a space for outBuf, + 1 for terminal null.
    
    *outPinyin = ( wchar_t* )malloc( ( inwLen * 8 + 1 ) * sizeof( wchar_t ) );
    wRealPinyin = ( wchar_t* )malloc( ( inwLen * 8 + 1 ) * sizeof( wchar_t ) );
    memset( *outPinyin, 0, ( inwLen * 8 + 1 ) * sizeof( wchar_t ) );
    memset( wRealPinyin, 0, ( inwLen * 8 + 1 ) * sizeof ( wchar_t ) );
    //the longest length of pinyin is 7,like "zhuang3",adding a " " make it 8
    
    int nFirstOfOutBuf, nFirstOfOutPinyin;
    nFirstOfOutBuf = inwLen * 2;
    nFirstOfOutPinyin = inwLen * 8;
    //the location of the first character in both buffer.

    while( wcslen(wInBuf) != 0 ){
        wchar_t* wWords = wInBuf;
        while( wcslen(wWords) > 0 && ( wPinyin = LookForWord(wWords) ) == NULL ) {    
            if( wcslen(wWords) == 1 )
	        break;
	    wWords++;
           //cut the fisrt character in wWords
        }

        nFirstOfOutBuf = nFirstOfOutBuf - wcslen(wSpace);
        wcsncpy( *outBuf + nFirstOfOutBuf, wSpace, wcslen( wSpace ) );
        nFirstOfOutBuf = nFirstOfOutBuf - wcslen(wWords);
        wcsncpy( *outBuf + nFirstOfOutBuf, wWords, wcslen( wWords ) );
         
        nFirstOfOutPinyin = nFirstOfOutPinyin - wcslen(wSpace);
        wcsncpy( *outPinyin + nFirstOfOutPinyin, wSpace, wcslen( wSpace ) );
	if( wPinyin != NULL ){
            nFirstOfOutPinyin = nFirstOfOutPinyin - wcslen(wPinyin);
            wcsncpy( *outPinyin + nFirstOfOutPinyin, wPinyin, wcslen( wPinyin ) );
	}	
	else{
	    nFirstOfOutPinyin = nFirstOfOutPinyin - wcslen(wStar);
            wcsncpy( *outPinyin + nFirstOfOutPinyin, wStar, wcslen( wStar ) );
	}
        wchar_t* wTmp;
        wTmp = wInBuf + wcslen( wInBuf ) - wcslen( wWords );
        wcsncpy( wTmp, L"\0", 1 );
        //cut wWords from the right of wInBuf.
    }
    
    wchar_t* wOut;
    wchar_t* wOutPinyin;
    
    for( wOut = *outBuf; wcsncmp( wOut, L"\0", 1 ) == 0; wOut++ );
    for( wOutPinyin = *outPinyin; wcsncmp( wOutPinyin, L"\0", 1 ) == 0; wOutPinyin++ );
    
    wcscpy( wRealOut, wOut );
    wcscpy( wRealPinyin, wOutPinyin );
    
    free( *outBuf );
    free( *outPinyin );   
   
    free( wInBuf );
    wInBuf = NULL;

    *outBuf = wRealOut;
    *outPinyin = wRealPinyin;
    return 0;
}

/**********************************************************
IsChinese : Decide whether wBuf is a Chinese Character.
Parameters : wchar_t* wBuf
             The character needed to be judged.
Return type : int
       value : 0 Chinese
               -1 no Chinese
Detail description : Using UCS4 standard to decide whether
a wchar_t is a Chinese or not.
**********************************************************/
int IsChinese( wchar_t* wBuf ){
    unsigned char cBuf[4];
    memcpy( cBuf, wBuf, 4 );    
    if( cBuf[2] >= 78 && cBuf[2] <= 159  )
        return 0;
    else 
	return -1;
}

/**********************************************************
IsEOL : Decide whether wBuf is the end of line.
Parameters : wchar_t* wBuf
	     The buffer needed to be judged.
Return type : int
       value : 0 EOL
               -1 no EOL
Detail description : compare it with '\n' or other EOL and
make the decision.
**********************************************************/
int IsEOL( wchar_t* wBuf ){
    char EOL[] = "\n";
    wchar_t wEOL[2];
    memset( wEOL, 0, 2 * sizeof( wchar_t ) );     
    int inLen = 1;
    int outLen = sizeof( wchar_t );
    char *pIn, *pOut;
    pIn = EOL;
    pOut = ( char* )wEOL;
    int nRet = convert( pIn, &inLen, pOut, &outLen, "UTF8", "UCS4" );
    if( nRet == -1 ){
	printf( "IsEOL convert failure!\n" );
	return -1;
    }  
    if( wcsncmp( wEOL, wBuf, 1 ) == 0 )
	return 0;
    else 
	return -1;
}
/**********************************************************
FirstToSecond : Give the wFirstBuf to ForwardCutwords or
BackwardCutWords function and store the result in wSecChiBuf 
and wSecPinBuf.
Parameters : wchar_t* wFirstBuf
             The buffer store string to be cut
             int *npFirstBufNum
             The volume of wFirstBuf
             int *npCurFirstBuf
             The number of characters in wFirstBuf
             wchar_t* wSecChiBuf
             The buffer store chinese result after cutting
             int* npSecChiBufNum
             The volume of wSecChiBuf
             int* npCurSecChiBuf
             The number of characters in wSecChiBuf
             wchar_t* wSecPinBuf
             The buffer store pinyin result after cutting
             int* npSecPinBufNum
             The volume of the wSecPinBuf
             int* npCurSecPinBuf
             The number of characters in wSecPinBuf
             int Mode 
             The algorithm user wanted to cut words
Return type : int
       value : 0 successful
               -1 failure
Detail description : This function is writen for the Transform 
function.It generates the first buffer to second buffer operation
which can be used in Transform function. 
**********************************************************/
int FirstToSecond( wchar_t* wFirstBuf, int* npFirstBufNum, int* npCurFirstBuf,
                   wchar_t** wSecChiBuf, int* npSecChiBufNum, int* npCurSecChiBuf,
                   wchar_t** wSecPinBuf, int* npSecPinBufNum, int* npCurSecPinBuf, int Mode, int WhichBuf ){
    wchar_t* wFirstChiBuf = NULL;
    wchar_t* wFirstPinBuf = NULL;

    wchar_t wSpace[2];
         
    if( WhichBuf == FIRSTCHI )/*For Chinese buffer we cut it*/{
	int nRet;
        switch( Mode ){
            case 1:
                nRet = ForwardCutWords( wFirstBuf, &wFirstChiBuf, &wFirstPinBuf );
                if( nRet == -1 ){
		    printf( "ForwardCutWords failure!\n" );
		    return -1;
		} 
 		break;
	     case 2:
		 nRet = BackwardCutWords( wFirstBuf, &wFirstChiBuf, &wFirstPinBuf );
		if( nRet == -1 ){
		    printf( "BackwardCutWords failure!\n" );
		    return -1;
                }
		break;
	      default:
	          break;
        	}
	}
    else{
        char space[] = " ";
        int inLen = strlen( space );
        int outLen = sizeof( wchar_t );
                
        char *pIn,*pOut;
        pIn = space;
        pOut = (char*)wSpace;
        memset( wSpace , 0, 2 * sizeof( wchar_t ) );
 
        int nRet = convert( pIn, &inLen, pOut, &outLen, "UTF8", "UCS4" );
        if( nRet == -1 ){
	    printf( "FirstToSecond convert space failure!\n" );
            return -1;
	}
    }
	//fill into wSecChiBuf, wSecPinBuf
	//both buffers are dynamic allocated
    int nChiLength,nPinLength;
        
    if( WhichBuf == FIRSTCHI ){    
        nChiLength = wcslen( wFirstChiBuf );
	nPinLength = wcslen( wFirstPinBuf );
    }
    else{
	nChiLength = nPinLength = wcslen( wFirstBuf ) + 1;
	//for other things we just add it to the end of second buffers plus a space
    }
    *npCurSecChiBuf += nChiLength;
    *npCurSecPinBuf += nPinLength;

    if( *npSecChiBufNum == 0 ){
	*npSecChiBufNum += nChiLength;
	*wSecChiBuf = ( wchar_t* )malloc( ( *npSecChiBufNum + 1 ) * sizeof( wchar_t ) );
	if( *wSecChiBuf == NULL ){
	    printf( "wSecChiBuf malloc failure!\n" );
	    return -1;
        }
	   
        memset( *wSecChiBuf, 0, ( *npSecChiBufNum + 1 ) * sizeof( wchar_t ) );
          
        *npSecPinBufNum += nPinLength;
        *wSecPinBuf = ( wchar_t* )malloc( ( *npSecPinBufNum + 1 ) * sizeof( wchar_t) );
	if( *wSecPinBuf == NULL ){
	    printf( "wSecPinBuf malloc failure!\n" );
	    return -1;
	}
	memset( *wSecPinBuf, 0, ( *npSecPinBufNum + 1 ) * sizeof( wchar_t ) );
	   
	if( WhichBuf == FIRSTCHI ){
	    wcscpy( *wSecChiBuf, wFirstChiBuf );
	    if( wFirstPinBuf != NULL )
	   	wcscpy( *wSecPinBuf, wFirstPinBuf );
	    else
		wcscpy( *wSecPinBuf, wSpace );
        }
        else{
	    wcscpy( *wSecChiBuf, wFirstBuf );
            wcscat( *wSecChiBuf, wSpace );
            wcscpy( *wSecPinBuf, wFirstBuf );
            wcscat( *wSecPinBuf, wSpace );
        }
    }
    else{	   
        if( *npCurSecChiBuf > *npSecChiBufNum ){
            *npSecChiBufNum = *npCurSecChiBuf;
	    *wSecChiBuf = ( wchar_t* )realloc( *wSecChiBuf, ( *npSecChiBufNum + 1 ) * sizeof( wchar_t ) );
	    if( *wSecChiBuf == NULL ){
	        printf( "wSecChiBuf realloc failure!\n" );
		return -1;
            }
               memset( (char*)( *wSecChiBuf + *npSecChiBufNum - nChiLength ), 0, ( nChiLength ) * sizeof( wchar_t ) );
	}          

        if( *npCurSecPinBuf > *npSecPinBufNum ){
            *npSecPinBufNum = *npCurSecPinBuf;
	    *wSecPinBuf = ( wchar_t* )realloc( *wSecPinBuf, ( *npSecPinBufNum + 1 ) * sizeof( wchar_t) );
	    if( *wSecPinBuf == NULL ){
	        printf( "wSecPinBuf realloc failure!\n" );
		return -1;
	    }
	    memset( (char*)( *wSecPinBuf + *npSecPinBufNum - nPinLength ), 0, ( nChiLength ) * sizeof( wchar_t ) );
        }
        if( WhichBuf == FIRSTCHI ){
	    wcscat( *wSecChiBuf, wFirstChiBuf );
	    wcscat( *wSecPinBuf, wFirstPinBuf );
        }
	else{
	    wcscat( *wSecChiBuf, wFirstBuf );
            wcscat( *wSecChiBuf, wSpace );
            wcscat( *wSecPinBuf, wFirstBuf );
            wcscat( *wSecPinBuf, wSpace );
        }	
    } 

    free(wFirstChiBuf);
    wFirstChiBuf = NULL;

    free(wFirstPinBuf);
    wFirstPinBuf = NULL;
 
    free( wFirstBuf );
    wFirstBuf = NULL;   
    *npFirstBufNum = 0;
    *npCurFirstBuf = 0;		
    //clean first buffer
    return 0;
}

/***********************************************************
SecondToOut : Combine wSecChiBuf and wSecPinBuf to wOutBuf
Parameters : wchar_t* wSecChiBuf
             The buffer store chinese words which has been 
             cut well.
             int* npSecChiBufNum
             The volume of wSecChiBuf
             int* npCurSecChiBuf
             The number of characters in wSecChiBuf
             wchar_t* wSecPinBuf
             The buffer store pinyin which has been cut well
             int* npSecPinBufNum
	     The volume of wSecPinBuf
             int* npCurSecPinBuf
             The number of characters inwSecPinBuf
             wchar_t* wOutBuf
             The buffer contains the combined result
             int* npOutBufNum
             The volume of wOutBuf
             int* npCurOutBuf
             The number of characters in wOutBuf
Return type : int
       value : 0 successful
               -1 failure
Detail description : This function is also written for Transform
function. It can facilitate the operation in Transform.     
***********************************************************/
int SecondToOut( wchar_t* wSecChiBuf, int* npSecChiBufNum, int* npCurSecChiBuf,          
                 wchar_t* wSecPinBuf, int* npSecPinBufNum, int* npCurSecPinBuf,
                 wchar_t** wOutBuf, int* npOutBufNum, int* npCurOutBuf){
    char EOL[] = "\n";
    int inLen = strlen( EOL );
    wchar_t wEOL[2];
    int outLen = sizeof( wchar_t );
    memset( wEOL, 0, 2 * sizeof( wchar_t ) );

    char *pIn, *pOut;
    pIn = EOL;
    pOut = ( char* )wEOL;

    int nRet = convert( pIn, &inLen, pOut, &outLen, "UTF8", "UCS4" );
    if( nRet == -1 ){
	printf( "SecondToOut convert failure!\n" );
	return -1;
    }
            
    if( *npCurSecChiBuf != 0 ){	 
        int nChiLength,nPinLength;
	nChiLength = wcslen( wSecChiBuf );
	nPinLength = wcslen( wSecPinBuf );

        *npCurOutBuf += nChiLength + nPinLength + 2;
            
        *wOutBuf = ( wchar_t* )realloc( *wOutBuf, ( *npCurOutBuf + 1 ) * sizeof( wchar_t ) );
        if( *wOutBuf == NULL ){
	    printf( "wOutBuf realloc failure!\n" );
	    return -1;
	}
	memset( (char*)( *wOutBuf + *npCurOutBuf - nChiLength - nPinLength - 2 ), 0, ( nChiLength + nPinLength + 2 ) * sizeof( wchar_t ) );
	    
	*npOutBufNum = *npCurOutBuf;
	wcscat( *wOutBuf, wSecChiBuf );
        wcscat( *wOutBuf, wEOL );
        wcscat( *wOutBuf, wSecPinBuf );
        wcscat( *wOutBuf, wEOL );

	free( wSecChiBuf );
	free( wSecPinBuf );
        wSecChiBuf = NULL;
        wSecPinBuf = NULL;

	*npSecChiBufNum = 0;
        *npSecPinBufNum = 0;
            
        *npCurSecChiBuf = 0;
        *npCurSecPinBuf = 0;
        //clean the second buffers.
    }
    else/*if just an EOL and nothing in second buffers, add an EOL to the end of outBuf*/{
        *npCurOutBuf += 1;
	*wOutBuf = ( wchar_t* )realloc( *wOutBuf, ( *npCurOutBuf + 1 ) * sizeof( wchar_t ) );
        if( *wOutBuf == NULL ){
	    printf( "SecondToOut wOutBuf realloc 2 failure!\n" );
	    return -1;
	}
	memset( (char*)( *wOutBuf + *npCurOutBuf - 1), 0, sizeof( wchar_t ) );
	*npOutBufNum = *npCurOutBuf;
	wcscat( *wOutBuf, wEOL );
    }
    return 0;   
}
/*******************************************************************
TransForm : the Interface of this module, which can cut the input to 
separate words and give them their pinyin.
Parameters : char* inBuf
             The input string
             int* inLen
             The length of input string
             char* outBuf
             The output string
             int *outLen 
             The length of output string
             int Mode
             The algorithm to be using
Return type : int
       value : 0 successful
              -1 failure
Detail description : When you input a string, this function will cut it
into separate words,and its pinyin will follow the cut string in the next 
line.There are two Mode available. 1 for maximum forward cutting algorithm,
2 for maximum backward cutting algorithm.REMEMBER to FREE outBuf when
finished.
*******************************************************************/
int TransForm( char* inBuf, int* inLen, char** outBuf, int* outLen, int Mode )/*Mode 1 Forward,Mode 2 Backward*/{
    wchar_t* wInBuf;
    wchar_t* wFirstBuf;
    wchar_t* wFirstOtherBuf;
    wchar_t* wSecChiBuf;
    wchar_t* wSecPinBuf;
    wchar_t* wOutBuf;
    //The three level buffer
    
    int nFirstBufNum;
    int nFirstOtherBufNum;
    int nSecChiBufNum;
    int nSecPinBufNum;
    int nOutBufNum;
    //The space of each buffer
    
    int nCurFirstBuf;
    int nCurFirstOtherBuf;
    int nCurSecChiBuf;
    int nCurSecPinBuf;
    int nCurOutBuf;
    //The current used number of each buffer
    
    int nRet;
      
    if( *inLen == 0 ){
	printf("TransForm got an null input string\n");
        return 0;
    }
    int nLength = (*inLen) * sizeof( wchar_t ) + sizeof( wchar_t );
    wInBuf = malloc( nLength );
    memset( wInBuf, 0, nLength );
    
    nRet = convert( inBuf, inLen, (char*)wInBuf, &nLength, "UTF8", "UCS4" );
    if( nRet == -1 ){
        printf( "TransForm convert from UTF8 to UCS4 failure!\n" );
        return -1;
    }
    //convert UTF8 to UCS4

    wchar_t* wIterator;
    wIterator = wInBuf;
    //The Iterator to walk through wInBuf
   
    nOutBufNum = 1;
    wOutBuf = ( wchar_t * )malloc( nOutBufNum * sizeof( wchar_t ) );
    if( wOutBuf == NULL ){
	printf( "wOutBuf malloc failure!\n" );
	return -1;
    }
    memset( wOutBuf, 0, nOutBufNum * sizeof( wchar_t ) );
    //Give the initial space

    nFirstBufNum = 0;
    nFirstOtherBufNum = 0;
    nSecChiBufNum = 0;
    nSecPinBufNum = 0;

    nCurFirstBuf = 0;
    nCurFirstOtherBuf = 0;
    nCurSecChiBuf = 0;
    nCurSecPinBuf = 0;
    nCurOutBuf = 0;
    //set the initial space and used number

    while( wcslen( wIterator ) != 0 ){
        if( IsChinese( wIterator ) == 0 ){
            if( nCurFirstOtherBuf != 0 ){
		nRet = FirstToSecond( wFirstOtherBuf, &nFirstOtherBufNum, &nCurFirstOtherBuf,
			     	      &wSecChiBuf, &nSecChiBufNum, &nCurSecChiBuf,
			     	      &wSecPinBuf, &nSecPinBufNum, &nCurSecPinBuf, Mode, FIRSTOTHER );
		if( nRet == -1 ){
		    printf( "FirstToSecond FIRSTOTHER failure!\n" );
		    return nRet;
		}
	    }
	    if( nFirstBufNum == 0 ){		
  	        nFirstBufNum = 100;
   	        wFirstBuf = ( wchar_t* )malloc( ( nFirstBufNum + 1 ) * sizeof( wchar_t ) );
   	        if( wFirstBuf == NULL ){
	 	    printf( "wFirstBuf malloc failure!\n" );
		    return -1;
    	        }
                memset( wFirstBuf, 0, ( nFirstBufNum + 1 ) * sizeof( wchar_t ) );
	    }
            nCurFirstBuf++;
            if( nCurFirstBuf > nFirstBufNum ){
		nFirstBufNum += 100;
                wFirstBuf = ( wchar_t* )realloc( wFirstBuf, ( nFirstBufNum + 1 ) * sizeof( wchar_t ) );
                if( wFirstBuf == NULL ){
		    printf( "realloc wFirstBuf failure!\n" );
		    return -1;
		}
		memset( ( char* )( wFirstBuf + nFirstBufNum - 100 ), 0, 100 * sizeof( wchar_t ) );
            }//if the wFirstBuf is not big enough, realloc it.
            wcsncat( wFirstBuf, wIterator, 1 );
	    wIterator++;
            continue;
        }
	
	//when it's not chinese do the cutting work and fill into wSecChiBuf,wSecPinBuf
        if( nCurFirstBuf != 0 ){
	    nRet = FirstToSecond( wFirstBuf, &nFirstBufNum, &nCurFirstBuf,
		     	      &wSecChiBuf, &nSecChiBufNum, &nCurSecChiBuf,
		     	      &wSecPinBuf, &nSecPinBufNum, &nCurSecPinBuf, Mode, FIRSTCHI );
	    if( nRet == -1 ){
		printf( "FirstToSecond FIRSHTCHI failure!\n" );
		return nRet;
	    }
	}
              
	if( IsEOL( wIterator ) == 0 ){	
            if( nCurFirstOtherBuf != 0 ){
		nRet = FirstToSecond( wFirstOtherBuf, &nFirstOtherBufNum, &nCurFirstOtherBuf,
			              &wSecChiBuf, &nSecChiBufNum, &nCurSecChiBuf,
			              &wSecPinBuf, &nSecPinBufNum, &nCurSecPinBuf, Mode, FIRSTOTHER );
            	if( nRet == -1 ){
		    printf( "FirstToSecond 2 FIRSTOTHER failure!\n" );
		    return nRet;
	    	} 
            }
	    nRet = SecondToOut( wSecChiBuf, &nSecChiBufNum, &nCurSecChiBuf,
				wSecPinBuf, &nSecPinBufNum, &nCurSecPinBuf,
				&wOutBuf, &nOutBufNum, &nCurOutBuf );
            if( nRet == -1 ){
		printf( " SecondToOut failure!\n" );
		return -1;
            }	           
	}
       	else{
            if( nFirstOtherBufNum == 0 ){		
  	        nFirstOtherBufNum = 100;
   		wFirstOtherBuf = ( wchar_t* )malloc( ( nFirstOtherBufNum + 1 ) * sizeof( wchar_t ) );
   	        if( wFirstOtherBuf == NULL ){
		    printf( "TransForm wFirstOtherBuf malloc failure!\n" );
		    return -1;
    		}
    		memset( wFirstOtherBuf, 0, ( nFirstOtherBufNum + 1 ) * sizeof( wchar_t ) );
	    }
            nCurFirstOtherBuf++;
            if( nCurFirstOtherBuf > nFirstOtherBufNum ){
		nFirstOtherBufNum += 100;
                wFirstOtherBuf = ( wchar_t* )realloc( wFirstOtherBuf, ( nFirstOtherBufNum + 1 ) * sizeof( wchar_t ) );
                if( wFirstOtherBuf == NULL ){
		    printf( "TransForm realloc wFirstOtherBuf failure!\n" );
		    return -1;
		}
		memset( ( char* )( wFirstOtherBuf + nFirstOtherBufNum - 100 ), 0, 100 * sizeof( wchar_t ) );
           }//if the wFirstBuf is not big enough, realloc it.
           wcsncat( wFirstOtherBuf, wIterator, 1 );
	}
	wIterator++;  
    }
    
    if( nCurFirstBuf != 0 ){
	nRet = FirstToSecond( wFirstBuf, &nFirstBufNum, &nCurFirstBuf,
			      &wSecChiBuf, &nSecChiBufNum, &nCurSecChiBuf,
			      &wSecPinBuf, &nSecPinBufNum, &nCurSecPinBuf, Mode, FIRSTCHI );
        if( nRet == -1 ){
	    printf( "FirstToSecond 2 FIRSTCHI failure!\n" );
	    return nRet;
	}
    }
    
    if( nCurFirstOtherBuf != 0 ){
	nRet = FirstToSecond( wFirstOtherBuf, &nFirstOtherBufNum, &nCurFirstOtherBuf,
			      &wSecChiBuf, &nSecChiBufNum, &nCurSecChiBuf,
			      &wSecPinBuf, &nSecPinBufNum, &nCurSecPinBuf, Mode, FIRSTOTHER );
        if( nRet == -1 ){
	    printf( "FirstToSecond 2 FIRSTOTHER failure!\n" );
	    return nRet;
	}
    }

    if( nCurSecChiBuf != 0 ){    
        nRet = SecondToOut( wSecChiBuf, &nSecChiBufNum, &nCurSecChiBuf,
				wSecPinBuf, &nSecPinBufNum, &nCurSecPinBuf,
				&wOutBuf, &nOutBufNum, &nCurOutBuf );
	if( nRet == -1 ){
	    printf( " SecondToOut 2 failure!\n" );
	    return -1;
	}    
    }
    
    //convert wOutBuf from "UCS4" to "UTF8"
    nLength = wcslen( wOutBuf );
    int nOutBufLength = nLength * sizeof( wchar_t );
    nLength = nOutBufLength;
    *outLen = nOutBufLength;

    *outBuf = ( char* )malloc( nOutBufLength + sizeof( wchar_t ) ); 
    memset( *outBuf, 0, nOutBufLength + sizeof( wchar_t ) );
  
    nRet = convert( (char*)wOutBuf, &nLength, *outBuf, &nOutBufLength, "UCS4", "UTF8" );
    if( nRet == -1 ){
	printf( "convert from UCS4 to UTF8 failure!\n" );
	return -1;
    }
   
    *outLen = *outLen - nOutBufLength;
    
    return 0;       
}  

/*
void main (){
    InitTrieTree();
    char buf[] = "我是一\n32424个并来SFAFA自老接口大家\n夫斯基大幅基督教分类撒接口邓丽君弗\n兰克搜集发静静的搜集法拉建立";
    int inlen = strlen(buf);
    int outlen;
    char *out;
    int nRet;

    nRet = TransForm( buf, &inlen, &out, &outlen, 2 );
    if( nRet == -1 )
        printf( "TransForm failure\n" );    
    else
	printf( "%s", out );
        
    free( out );
}*/


